#include "stm32f10x.h"                  // Device header

#include "Delay.h"

static uint16_t Encoder_Count = 0;

void Encoder_Init(void)
{
	// 第一步：配置RCC，将涉及到的外设的时钟都打开，不打开时钟外设是无法工作的。
	//         其中 EXTI 和 NVIC 的时钟一直是开着的不用处理。
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);   // 开启 APB2 下的 GPIOB 的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);    // 开启 APB2 下的 AFIO  的时钟
	
	
	// 第二步：配置GPIO，选择我们的端口为输入模式。
	// 外部中断推荐的 GPIO 输入模式为 上拉、下拉、浮空.
	GPIO_InitTypeDef GPIO_Init_Structure;
	GPIO_Init_Structure.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Init_Structure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
	GPIO_Init_Structure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_Init_Structure);
	
	// 第三步：配置 AFIO，选择我们用的这一路 GPIO，连接到后面的 EXTI。
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);   // 将第 0 个线路拨到 GPIOB 上
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);   // 将第 1 个线路拨到 GPIOB 上
	
	// 第四步：配置EXTI，选择边沿触发方式，比如上升沿、下降沿 或者 双边沿。  选择触发响应方式，可以选择中断响应 和 事件响应。 
	EXTI_InitTypeDef EXTI_InitStructure;
	EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;// 第 0 个和 第 1 个线路都初始化为中断模式, 下降沿触发。
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;    // 中断响应还是事件响应
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;// 指定触发中断的有效边沿
	EXTI_Init(&EXTI_InitStructure);
	
	// 第五步：配置 NVIC，给我们这个中断选择一个合适的优先级。
	// 分组方式整个芯片只能用一组.
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);        // 优先级分组选择
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;       // 指定通道 0
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        // 指定通道是使能还是失能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  // 指定抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;      // 指定响应优先级
	NVIC_Init(&NVIC_InitStructure);
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;       // 指定通道 1
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        // 指定通道是使能还是失能
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  // 指定抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;      // 指定响应优先级
	NVIC_Init(&NVIC_InitStructure);
}


void EXTI0_IRQHandler(void)
{
	// A 发生下降沿, 此时判断另一个 B 引脚的电平, 要加软件消抖
	Delay_ms(3);
	if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0 && GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
	{
		Encoder_Count--;
	}
	
	// 一定要清除中断标志, 否则程序会卡在中断标志中
	EXTI_ClearITPendingBit(EXTI_Line0);
	
}

void EXTI1_IRQHandler(void)
{
	// B 发生下降沿, 此时判断另一个 A 引脚的电平
	Delay_ms(3);
	if( GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0 && GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
	{
		Encoder_Count++;
	} 
	
	// 一定要清除中断标志, 否则程序会卡在中断标志中
	EXTI_ClearITPendingBit(EXTI_Line1);
}


int16_t Encoder_Get(void)
{
	int16_t temp = 0;
	temp = Encoder_Count;
	Encoder_Count = 0;
	return temp;
}